home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_ImportAdv / ImportApp.m < prev    next >
Encoding:
Text File  |  1992-12-19  |  14.3 KB  |  722 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    ImportApp.m
  35.  *
  36.  *    This class performs some of the global functions necessary to
  37.  *    manage the application.
  38.  *
  39.  *    Several application wide resources are retained as
  40.  *    instance variables. Examples are the hitPoint and
  41.  *    upathBuffer buffers and the hitSetting value.
  42.  *
  43.  *    Version:    2.0
  44.  *    Author:    Ken Fromm
  45.  */
  46.  
  47. #import "ImportApp.h"
  48. #import "Document.h"
  49. #import "DrawingView.h"
  50. #import "ImportPanel.h"
  51. #import "Preferences.h"
  52. #import "SaveAsPanel.h"
  53.  
  54. #import "DrawingViewWraps.h"
  55.  
  56. #import <appkit/NXCursor.h>
  57. #import <appkit/NXImage.h>
  58. #import <appkit/Matrix.h>
  59. #import <appkit/Menu.h>
  60. #import <appkit/MenuCell.h>
  61. #import <appkit/defaults.h>
  62. #import <appkit/nextstd.h>
  63.  
  64. #import <objc/List.h>
  65. #import <sys/param.h>
  66. #import <string.h>
  67.  
  68. struct  cursorRecord {
  69.      char        *name;
  70.     NXPoint    hotspot;
  71. };
  72.  
  73. const static struct cursorRecord cursors[] = {
  74.     {NULL, 0.0, 0.0},                /* Select */
  75.     {"cursorZoomUp.tiff", 8.0, 8.0},
  76.     {"cursorRotate1.tiff", 8.0, 8.0},
  77.     {"cursorZoomDown.tiff", 8.0, 8.0},
  78.     {"cursorRotate2.tiff", 6.0, 4.0},
  79.     {"cursorImport.tiff", 2.0, 1.0},
  80.     {NULL, 0.0, 0.0}                /* Place */
  81. };
  82.  
  83. char    ControlFont[ ] = "ControlPointsFont";
  84.  
  85. @implementation ImportApp
  86.  
  87. /*
  88.  * Sets the updateAction for every menu item which sends to the
  89.  * First Responder (i.e. their target is nil).  When autoupdate is on,
  90.  * every event will be followed by an update of each of the menu items
  91.  * which is visible.  This keep all unavailable menu items dimmed out
  92.  * so that the user knows what options are available at any given time.
  93.  * Returns the activate menu if is found in this menu.
  94.  */ 
  95. static void initMenu(id menu)
  96. {
  97.     int             count;
  98.     id             matrix, cell;
  99.     id            matrixTarget, cellTarget;
  100.  
  101.     matrix = [menu itemList];
  102.     matrixTarget = [matrix target];
  103.  
  104.     count = [matrix cellCount];
  105.     while (count--)
  106.     {
  107.         cell = [matrix cellAt:count :0];
  108.         cellTarget = [cell target];
  109.         if (!matrixTarget && !cellTarget)
  110.             [cell setUpdateAction:@selector(menuItemUpdate:) forMenu:menu];
  111.         else if ([cell hasSubmenu])
  112.             initMenu(cellTarget);
  113.     }
  114. }
  115.  
  116. /*
  117.  *    Checks to see if the passed window's delegate is a Document
  118.  *    instance. If it is, it returns that document, otherwise it returns nil.
  119.  */
  120. static id documentInWindow(id window)
  121. {
  122.     id         document = [window delegate];
  123.     
  124.     return [document  isKindOf:[Document class]] ? document : nil;
  125. }
  126.  
  127. /*
  128.  *    Searches the window list looking for a Document with the specified
  129.  *    name. Returns the window containing the document if found.
  130.  *    If name == NULL then the first document found is returned.
  131.  */
  132. static id findDocument(const char *name)
  133. {
  134.     int         count;
  135.     id         document, window, windowList;
  136.  
  137.     windowList = [NXApp windowList];
  138.     count = [windowList count];
  139.     while (count--)
  140.     {
  141.         window = [windowList objectAt:count];
  142.         document = documentInWindow(window);
  143.     
  144.         if (document && (!name || !strcmp([document filename], name))) 
  145.             return window;
  146.     }
  147.  
  148.     return nil;
  149. }
  150.  
  151. /*
  152.  *    Opens a file with the given name in the specified directory.
  153.  *    If we already have that file open, it is ordered front.
  154.  *    Returns the document if successful, nil otherwise.
  155.  */
  156. static id openFile(const char *directory, const char *name, BOOL display)
  157. {
  158.     id        window;
  159.  
  160.     char        buffer[MAXPATHLEN+1], path[MAXPATHLEN+1];
  161.  
  162.     if (name && *name)
  163.     {
  164.         if (!directory)
  165.         {
  166.             directory = ".";
  167.         } 
  168.         else if (*directory != '/')
  169.         {
  170.             strcpy(buffer, "./");
  171.             strcat(buffer, directory);
  172.             directory = buffer;
  173.         }
  174.     
  175.         if (!chdir(directory) && getwd(path))
  176.         {
  177.             strcat(path, "/");
  178.             strcat(path, name);
  179.             window = findDocument(path);
  180.             if (window)
  181.             {
  182.                 if (display)
  183.                     [window makeKeyAndOrderFront:window];
  184.                 return [window delegate];
  185.             } 
  186.             else
  187.                 return [Document newFromFile:path];
  188.         } 
  189.         else 
  190.             NXRunAlertPanel("Open", "Invalid path: %s", "OK", NULL, NULL, directory);
  191.     }
  192.  
  193.     return nil;
  194. }
  195.  
  196. /*
  197. *     Allocate a buffer for use by any drawing view to send
  198. *     data to the PostScript server.
  199. *
  200. *    Allocate this buffer for use by any drawing view to
  201. *    use as the hitdetection userpath. Initialize the description
  202. *    since most of the components will remain the same.
  203. */
  204. + new
  205. {
  206.     int        i;
  207.  
  208.     self = [super new];
  209.  
  210.     [self setAutoupdate:YES];
  211.  
  212.     PSWDefineFont(ControlFont);
  213.     hitSetting = 4.0;
  214.     contextFlag = imagingFlag = YES;
  215.  
  216.     NX_MALLOC(upathBuffer.pts, float, PTS_BUFFER);
  217.     NX_MALLOC(upathBuffer.ops, char, OPS_BUFFER);
  218.  
  219.     NX_MALLOC(hitPoint.pts, float, PTS_HITPOINT);
  220.     NX_MALLOC(hitPoint.ops, char, OPS_HITPOINT);
  221.  
  222.     for (i = 0; i < PTS_HITPOINT; i++)
  223.         hitPoint.pts[i] = 0;            
  224.     hitPoint.num_pts = i;
  225.      
  226.     i = 0;
  227.     hitPoint.ops[i++] = dps_setbbox;
  228.     hitPoint.ops[i++] = dps_moveto;
  229.     hitPoint.ops[i++] = dps_rlineto;
  230.     hitPoint.ops[i++] = dps_rlineto;
  231.     hitPoint.ops[i++] = dps_rlineto;
  232.     hitPoint.ops[i++] = dps_closepath;
  233.     hitPoint.num_ops = i;
  234.  
  235.     return self;
  236. }
  237.  
  238. /*  Initializes the defaults. */
  239. + initialize
  240. {
  241.     const NXDefaultsVector EpsfDefaults = {
  242.         { "Quit", NULL },
  243.         { NULL, NULL }
  244.     };
  245.  
  246.     NXRegisterDefaults("Epsf", EpsfDefaults);
  247.  
  248.     return self;
  249. }
  250.  
  251. - free
  252. {
  253.     if (upathBuffer.pts)
  254.         NX_FREE(upathBuffer.pts);
  255.     if (upathBuffer.ops)
  256.         NX_FREE(upathBuffer.ops);
  257.     if (hitPoint.pts)
  258.         NX_FREE(hitPoint.pts);
  259.     if (hitPoint.ops)
  260.         NX_FREE(hitPoint.ops);
  261.  
  262.     return [super free];
  263. }
  264.  
  265. - setToolPanel:anObject
  266. {
  267.     toolpanelId = anObject;
  268.  
  269.     return self;
  270. }
  271.  
  272. - setToolMatrix:anObject
  273. {
  274.     toolmatrixId = anObject;
  275.  
  276.     return self;
  277. }
  278.  
  279. - setSaveAccessory:anObject
  280. {    
  281.     [[SaveAsPanel new]  setAccessoryView:anObject];
  282.  
  283.     return self;
  284. }
  285.  
  286. - setImportAccessory:anObject
  287. {    
  288.     [[ImportPanel  new]  setImportAccessory:anObject];
  289.  
  290.     return self;
  291. }
  292.  
  293. /* Calculate the position for the next window. */
  294. - getPosition:(NXPoint *)location  forSize:(NXSize *)winSize
  295. {
  296.     int        col, row;
  297.     
  298.     col = (numWindows/NUMPERCOL) % NUMCOLUMNS;
  299.     row = numWindows % NUMPERCOL;
  300.     
  301.     location->x = WINDOWSTARTX + (col * OFFSETLEFT) + (row * OFFSETX);
  302.     location->y = WINDOWSTARTY - winSize->height - (row * OFFSETY);
  303.  
  304.     numWindows++;
  305.  
  306.     return self;
  307. }
  308.  
  309. /*
  310. *    Teaching aids
  311. */
  312. - setContextFlag:sender
  313. {
  314.     if (!contextFlag)
  315.         [[sender selectedCell] setTitle:"Separate Context On"];
  316.     else
  317.         [[sender selectedCell] setTitle:"Separate Context Off"];
  318.  
  319.     contextFlag = !contextFlag;
  320.     
  321.     return self;
  322. }
  323.  
  324. - (BOOL) contextFlag
  325. {
  326.     return contextFlag;
  327. }
  328.  
  329. - setShowEpsfFlag:sender
  330. {
  331.     if (!showEpsfFlag)
  332.         [[sender selectedCell] setTitle:"Show Epsf On"];
  333.     else
  334.         [[sender selectedCell] setTitle:"Show Epsf Off"];
  335.  
  336.     showEpsfFlag = !showEpsfFlag;
  337.  
  338.     return self;
  339. }
  340.  
  341. - (BOOL) showEpsfFlag
  342. {
  343.     return showEpsfFlag;
  344. }
  345.  
  346. - setShowBufferFlag:sender
  347. {
  348.     if (!showBufferFlag)
  349.         [[sender selectedCell] setTitle:"Show Buffer On"];
  350.     else
  351.         [[sender selectedCell] setTitle:"Show Buffer Off"];
  352.  
  353.     showBufferFlag = !showBufferFlag;
  354.  
  355.     if (showBufferFlag)
  356.         [[[self  currentDocument]  drawingView]  showBuffer:self];
  357.     else
  358.         [[[self  currentDocument]  drawingView]  hideBuffer:self];
  359.  
  360.     return self;
  361. }
  362.  
  363. - (BOOL) showBufferFlag
  364. {
  365.     return showBufferFlag;
  366. }
  367.  
  368. /*    Change the menu title and toggle the trace boolean.    */
  369. - setTracingFlag:sender
  370. {
  371.     if (!tracingFlag)
  372.         [[sender selectedCell] setTitle:"Trace On"];
  373.     else
  374.         [[sender selectedCell] setTitle:"Trace Off"];
  375.  
  376.     tracingFlag = !tracingFlag;
  377.     
  378.     return self;
  379. }
  380.  
  381. - (BOOL) tracingFlag
  382. {
  383.     return tracingFlag;
  384. }
  385.  
  386. - setImagingFlag:sender
  387. {
  388.     imagingFlag = [sender  state];
  389.     [[[self  currentDocument]  drawingView]  display];
  390.  
  391.     return self;
  392. }
  393.  
  394. - (BOOL) imagingFlag
  395. {
  396.     return imagingFlag;
  397. }
  398.  
  399. - setHitSetting:sender
  400. {
  401.      hitSetting = [sender  floatValue];
  402.  
  403.     return self;
  404. }
  405.  
  406. - (float) hitSetting
  407. {
  408.     return hitSetting;
  409. }
  410.  
  411. - (UPath *) hitPoint;
  412. {
  413.     return &hitPoint;
  414. }
  415.  
  416. - (UPath *) upathBuffer;
  417. {
  418.     return &upathBuffer;
  419. }
  420.  
  421. - currentDocument
  422. {
  423.     return documentInWindow(mainWindow);
  424. }
  425.  
  426. - (const char *)currentDirectory
  427. {
  428.     const char *retval = [[self  currentDocument] directory];
  429.  
  430.     if (!retval || !*retval)
  431.         retval = [[OpenPanel new] directory];
  432.  
  433.     return retval;
  434. }
  435.  
  436. /* Open a new document. */
  437. - new:sender
  438. {
  439.     [Document new];
  440.  
  441.     return self;
  442. }
  443.  
  444. /*
  445.  * Called by pressing Open... in the Window menu.
  446.  */
  447. - open:sender
  448. {
  449.     id            openpanel;
  450.  
  451.     char            path[MAXPATHLEN+1];
  452.  
  453.     const char        *directory;
  454.  
  455.     const char *const        *files;
  456.  
  457.     static const char *const        filetype[2] = {"adb", NULL};
  458.  
  459.     directory = NULL;
  460.     directory = [[self  currentDocument]  directory];
  461.     if (!directory)
  462.         if (getwd(path))
  463.             directory = path;
  464.      openpanel = [[ImportPanel  new]  setOpen];
  465.          if ([openpanel  runModalForDirectory:directory  file:NULL  types:filetype])
  466.     {
  467.         files = [openpanel filenames];
  468.         directory = [openpanel directory];
  469.         while (files && *files)
  470.         {
  471.             openFile(directory, *files, YES);
  472.             files++;
  473.         }
  474.     }
  475.  
  476.     return self;
  477. }
  478.  
  479. /*
  480.  *    Sends a windowWillClose message to all open Documents
  481.  *    before the program terminates.
  482.  */
  483. - terminate:sender
  484. {
  485.     int        count;
  486.     id        window, document;
  487.  
  488.     count = [windowList count];
  489.     while (count--)
  490.     {
  491.         window = [windowList  objectAt:count];
  492.         document = documentInWindow(window);
  493.         if (document)
  494.         {
  495.             if ([document  windowWillClose:window])
  496.                 [window close];
  497.             else
  498.                 return self;
  499.         }
  500.     }
  501.  
  502.     return [super terminate:sender];
  503. }
  504.  
  505. - setTool:sender
  506. {
  507.     [self  setOperation:[sender  selectedTag]];
  508.  
  509.     return self;
  510. }
  511.  
  512. - resourcePanel
  513. {
  514.     if (!resourcePanel)
  515.         [NXApp  loadNibSection:"ResourcePanel.nib"  owner:self  withNames:NO];
  516.  
  517.     return resourcePanel;
  518. }
  519.  
  520. /*
  521. *    Return the cursor for the appropriate index. Create
  522. *    one if non-existent.
  523. */
  524. - getCursor:(int) index
  525. {
  526.     id        imageId;
  527.  
  528.     if (!cursorIds[index])
  529.     {
  530.         if (cursors[index].name)
  531.         {
  532.             imageId = [NXImage  newFromSection:cursors[index].name];
  533.             cursorIds[index]= [NXCursor  newFromImage:imageId];
  534.             [cursorIds[index]  setHotSpot:&cursors[index].hotspot];
  535.         }
  536.     }
  537.  
  538.     return cursorIds[index];
  539. }
  540.     
  541. - cursor
  542. {
  543.     id        imageId;
  544.  
  545.     if (!cursorIds[operation])
  546.     {
  547.         if (cursors[operation].name)
  548.         {
  549.             imageId = [NXImage  newFromSection:cursors[operation].name];
  550.             cursorIds[operation]= [NXCursor  newFromImage:imageId];
  551.             [cursorIds[operation]  setHotSpot:&cursors[operation].hotspot];
  552.         }
  553.         else
  554.             cursorIds[operation] = NXArrow;
  555.     }
  556.  
  557.     return cursorIds[operation];
  558. }
  559.  
  560. - (int) operation
  561. {       
  562.     return operation;
  563. }
  564.  
  565. - setOperation:(int) newOperation
  566. {
  567.     id        currentDoc;
  568.  
  569.     if (newOperation < OP_FIRST || newOperation > OP_LAST)
  570.         newOperation = OP_SELECT;
  571.     operation = newOperation;
  572.  
  573.     currentDoc = [self  currentDocument];
  574.     [[currentDoc  window]  invalidateCursorRectsForView:[currentDoc drawingView]];
  575.  
  576.     return self;
  577. }
  578.  
  579. - clearOperation
  580. {
  581.     [self  setOperation:OP_SELECT];
  582.     [toolmatrixId  selectCellWithTag:OP_SELECT];
  583.  
  584.     return self;
  585. }
  586.  
  587. /*
  588.  * Application object delegate methods.
  589.  * Messages that would be sent to the delegate are sent to the Application
  590.  * object or a subclass if no delagate exists. 
  591.  */
  592.  
  593. /*
  594.  * Initialize the menus.
  595.  * Sets the tool palette so it never becomes the key window.
  596.  * Check for files to open specified on the command line.
  597.  * If there are no open documents, then open a blank one.
  598.  */
  599. - appDidInit:sender
  600. {
  601.     id            docId;
  602.     int            i;
  603.     char            buffer[MAXPATHLEN+1];
  604.     char            *directory, *name, *ext;
  605.  
  606.     [toolpanelId  removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK];
  607.     [toolpanelId  orderFront:self];
  608.  
  609.     initMenu([NXApp mainMenu]);
  610.  
  611.     if (NXArgc > 1)
  612.     {
  613.         for (i = 1; i < NXArgc; i++)
  614.         {
  615.             strcpy(buffer, NXArgv[i]);
  616.             ext = strrchr(buffer, '.');
  617.             if (!ext || strcmp(ext, ".adb"))
  618.                 strcat(buffer, ".adb");
  619.     
  620.             name = strrchr(buffer, '/');
  621.  
  622.             if (name)
  623.             {
  624.                 *name++ = '\0';
  625.                 directory = buffer;
  626.             } 
  627.             else
  628.             {
  629.                 name = buffer;
  630.                 directory = NULL;
  631.             }
  632.             docId = openFile(directory, name, YES);
  633.         }
  634.     }
  635.     
  636.     /* if none opened, open one */
  637.     if (!findDocument(NULL))
  638.         [self new:self];    
  639.     
  640.     if (NXGetDefaultValue([self appName], "Quit"))
  641.     {
  642.         [self activateSelf:YES];
  643.         NXPing();
  644.         [self terminate:self];
  645.     }
  646.  
  647.     return self;
  648. }
  649.  
  650. /*
  651.  * This method is performed whenever a user double-clicks on an icon
  652.  * in the Workspace Manager representing an Epsf document.
  653.  */
  654. - (int)appOpenFile:(const char *)path type:(const char *)type
  655. {
  656.     char        *name;
  657.     char        directory[MAXPATHLEN+1];
  658.  
  659.     if (type && !strcmp(type, "adb"))
  660.     {
  661.         strcpy(directory, path);
  662.         name = strrchr(directory, '/');
  663.         if (name)
  664.         {
  665.             *name++ = '\0';
  666.             return (openFile(directory, name, YES) ? YES : NO);
  667.         }
  668.     }
  669.  
  670.     return NO;
  671. }
  672.  
  673. /*  We accept any number of appOpenFile:type: messages. */
  674. - (BOOL)appAcceptsAnotherFile:sender
  675. {
  676.     return YES;
  677. }
  678.  
  679. /* Automatic update methods */
  680.  
  681. /*
  682.  * Method called by all menu items which send their actions to the
  683.  * First Responder.  First, if the object which would respond were the
  684.  * action sent down the responder chain also responds to the message
  685.  * validateCommand:, then it is sent validateCommand: to determine
  686.  * whether that command is valid now, otherwise, if there is a responder
  687.  * to the message, then it is assumed that the item is valid.
  688.  * The method returns YES if the cell has changed its appearance (so that
  689.  * the caller (a Menu) knows to redraw it).
  690.  */
  691. - (BOOL)menuItemUpdate:menuCell
  692. {
  693.     SEL            action;
  694.     id            responder, target;
  695.     BOOL        enable;
  696.  
  697.     target = [menuCell  target];
  698.     enable = [menuCell  isEnabled];
  699.  
  700.     if (!target)
  701.     {
  702.         action = [menuCell action];
  703.         responder = [self calcTargetForAction:action];
  704.     
  705.         if ([responder respondsTo:@selector(validateCommand:)])
  706.             enable = [responder validateCommand:menuCell];
  707.         else
  708.             enable = responder ? YES : NO;
  709.     }
  710.  
  711.     if ([menuCell isEnabled] != enable)
  712.     {
  713.         [menuCell setEnabled:enable];
  714.         return YES;
  715.     }
  716.     else
  717.         return NO;
  718. }
  719.  
  720. @end
  721.  
  722.